﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;
using System.Windows.Media.Media3D;

namespace RLProject1.Model.Utility
{
    public class Mesh
    {
        internal const int INITIAL_CAPACITY = 256;

        private List<Vector3D> _vertices;
        /// <summary>The vertices read only collection.</summary>
        private ReadOnlyCollection<Vector3D> vertices;
        /// <summary>
        /// Gets the collection of vertices. Each vertex has a corresponding normal with the same index.
        /// </summary>
        public ReadOnlyCollection<Vector3D> Vertices
        {
            get {
                if (vertices == null)
                {
                    vertices = new ReadOnlyCollection<Vector3D>(_vertices);
                }
                return vertices;
            }
        }

        private List<Vector3D> _normals;
        /// <summary>The normals read only collection.</summary>
        private ReadOnlyCollection<Vector3D> normals;
        /// <summary>
        /// Gets the collection of normals. Each normal has a corresponding vertex with the same index.
        /// </summary>
        public ReadOnlyCollection<Vector3D> Normals
        {
            get
            {
                if (normals == null)
                {
                    normals = new ReadOnlyCollection<Vector3D>(_normals);
                }
                return normals;
            }
        }


        private List<int> _tirangleIndexes;
        /// <summary>The triangle indexes read only collection.</summary>
        private ReadOnlyCollection<int> triangleIndexes;
        /// <summary>
        /// Gets the collection of triangle indexes. There are 3 indexes per triangle.
        /// </summary>
        public ReadOnlyCollection<int> TriangleIndexes
        {
            get {
                if (triangleIndexes == null)
                {
                    triangleIndexes = new ReadOnlyCollection<int>(_tirangleIndexes);
                }
                return triangleIndexes;
            }
        }


        /// <summary>
        /// Initializes a new instance of the Mesh class.
        /// </summary>
        public Mesh()
        {
            _vertices = new List<Vector3D>(INITIAL_CAPACITY);
            _normals = new List<Vector3D>(INITIAL_CAPACITY);
            _tirangleIndexes = new List<int>(2 * INITIAL_CAPACITY);
        }


        internal void AddVertex(Vector3D vertex)
        {
            _vertices.Add(vertex);
            vertices = null;
        }

        internal void AddNormal(Vector3D normal)
        {
            _normals.Add(normal);
            normals = null;
        }

        internal void AddTriangleIndexes(int idx0, int idx1, int idx2)
        {
            _tirangleIndexes.AddRange(new int[] { idx0, idx1, idx2 });
            triangleIndexes = null;
        }

        public override string ToString()
        {
            StringBuilder str = new StringBuilder();
            str.AppendLine("#" + Environment.NewLine + "# OBJ file created by RLProject1" + Environment.NewLine + "#" + Environment.NewLine);
            str.AppendLine("# List of Vertices, with (x,y,z) coordinates");
            foreach (Vector3D vector in _vertices)
            { //CultureInfo.GetCultureInfo("en").NumberFormat;
                str.AppendFormat(NumberFormatInfo.InvariantInfo, "v {0} {1} {2}", vector.X, vector.Y, vector.Z);
                str.Append(Environment.NewLine);
            }
            str.AppendLine();
            str.AppendLine("# Normals in (x,y,z) form; normals might not be unit.");
            foreach (Vector3D vector in _normals)
            {
                str.AppendFormat(NumberFormatInfo.InvariantInfo, "vn {0} {1} {2}", vector.X, vector.Y, vector.Z);
                str.Append(Environment.NewLine);
            }
            str.AppendLine();
            str.AppendLine("# Face Definitions Vertex//Normal");
            int index = 0;
            while (index + 2 < _tirangleIndexes.Count)
            {
                str.AppendFormat("f {0}//{0} {1}//{1} {2}//{2}", _tirangleIndexes[index], _tirangleIndexes[index + 1], _tirangleIndexes[index + 2]);
                str.Append(Environment.NewLine);
                index += 3;
            }
            return str.ToString();
        }

    }
}
